package br.usp.pcs.basys2.processor;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import br.usp.pcs.basys2.BasysProcess;
import br.usp.pcs.basys2.engine.Engine;

public class ProcessorManager {

	private Queue<BasysProcess> readyList = new LinkedList<BasysProcess>();
	private Integer timeSlice = 500;
	private BasysProcess runningProcess = null;
	private List<ProcessorManagerListener> listeners = new ArrayList<ProcessorManagerListener>();

	public boolean add(ProcessorManagerListener e) {
		return listeners.add(e);
	}

	public void requestProcess(BasysProcess process) {
		if (processorIsFree()) {
			run(process);
		} else {
			String effect = "Process " + process + " has been Queued by "
					+ this.getClass().getSimpleName();
			Engine.getInstance().getCurrentOutputBlock().add(effect);
			readyList.add(process);
		}
	}

	private void run(BasysProcess basysProcess) {
		if (basysProcess == null) {
			throw new IllegalArgumentException();
		}
		notifyStoppedProcess(runningProcess);
		runningProcess = basysProcess;
		for (ProcessorManagerListener listener : listeners) {
			listener.onProcessStartedRunning(basysProcess, timeSlice);
		}

	}

	private void notifyStoppedProcess(BasysProcess basysProcess) {
		if (basysProcess != null) {
			for (ProcessorManagerListener listener : listeners) {
				listener.onProcessStoppedRunning(basysProcess);
			}
		}
	}

	private void notifyFinishedProcess(BasysProcess basysProcess) {
		if (runningProcess != null) {
			for (ProcessorManagerListener listener : listeners) {
				listener.onProcessIsFinished(runningProcess);
			}
		}
	}

	public void interruptReached(BasysProcess process) {
		if (!process.equals(runningProcess)) {
			if (runningProcess != null)
				readyList.add(runningProcess);
		}

		if (!readyList.isEmpty()) {
			run(readyList.poll());
		} else {
			// bloqueia processo
			notifyStoppedProcess(runningProcess);
			runningProcess = null;
		}
	}

	public void advanceQueue() {
		if (runningProcess!=null){
			readyList.add(runningProcess);
		}
		String effect = this.getClass().getSimpleName() + " is advancing Queue";
		Engine.getInstance().getCurrentOutputBlock().add(effect);
		BasysProcess nextProcess = readyList.poll();
		if (nextProcess!=null){
			run(nextProcess);
		}
	}

	public void processFinished(BasysProcess basysProcess) {
		//notifyStoppedProcess(basysProcess);
		notifyFinishedProcess(basysProcess);
		if (!readyList.isEmpty()) {
			run(readyList.poll());
		} else {
			// bloqueia processo
			notifyStoppedProcess(basysProcess);
			runningProcess = null;
			
		}
	}

	public Integer getTimeSlice() {
		return timeSlice;
	}

	public boolean processorIsFree() {
		return runningProcess == null;
	}

	public BasysProcess getRunningProcess() {
		return runningProcess;
	}
}
